package main

import (
	"climit/climit"
	"fmt"
	"os"
	"path"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"time"
)

var reindexDirectoryOption = climit.BoolOption{
	ShortName:   "d",
	LongName:    "reindexDirectory",
	Description: "是否操作目录",
}

var reindexFileOption = climit.BoolOption{
	ShortName:   "f",
	LongName:    "reindexFile",
	Description: "是否操作文件",
}

func main() {
	rootCommand := climit.RootCommand{
		Description: "重新排序资源的小工具",
		Options: []climit.Option{
			reindexDirectoryOption,
			reindexFileOption,
			climit.BoolOption{
				ShortName:   "r",
				LongName:    "recurve",
				Description: "是否递归处理子目录",
			},
			climit.BoolOption{
				ShortName:   "i",
				LongName:    "initIndex",
				Description: "是否初始化索引",
			},
			climit.BoolOption{
				ShortName:   "",
				LongName:    "noIgnorePrefix",
				Description: "重排序的时候不忽略任何前缀，默认情况下会忽略'_'前缀",
			},
			climit.OptionalStringOption{
				ShortName:   "",
				LongName:    "ignorePrefix",
				Description: "排序是忽略的名称前缀",
			},
			climit.OptionalStringOption{
				ShortName:   "",
				LongName:    "ignoreSuffix",
				Description: "排序时忽略的名称后缀",
			},
			climit.OptionalStringOption{
				ShortName:   "",
				LongName:    "ignoreRegexp",
				Description: "",
			},
		},
		Run: func(commandDescriptor climit.CommandDescriptor) {
			args := parseReindexParams(commandDescriptor)
			reindex(args.workDir, args)
		},

		SubCommands: []climit.Command{
			{
				Name:        "moveAfter",
				Description: "移动到xx后",
				Options: []climit.Option{
					reindexDirectoryOption,
					reindexFileOption,
				},
				Run: runMoveAfter,
			},
			{
				Name:        "moveBefore",
				Description: "移动到xx之前",
				Options: []climit.Option{
					reindexDirectoryOption,
					reindexFileOption,
				},
				Run: runMoveBefore,
			},
			{
				Name:        "moveToTop",
				Description: "移动到开头",
				Options: []climit.Option{
					reindexDirectoryOption,
					reindexFileOption,
				},
				Run: runMoveToTop,
			},
			{
				Name:        "moveToBottom",
				Description: "移动到末尾",
				Options: []climit.Option{
					reindexDirectoryOption,
					reindexFileOption,
				},
				Run: runMoveToBottom,
			},
			{
				Name:        "unIndex",
				Description: "取消排序",
				Options: []climit.Option{
					reindexDirectoryOption,
					reindexFileOption,
					climit.OptionalStringOption{
						LongName:    "newPrefix",
						Description: "新前缀",
					},
				},
				Run: runUnIndex,
			},
		},
	}

	rootCommand.Execute()
}

var indexedNameRegexp, _ = regexp.Compile("^[0-9]+-.?")
var spaceRegexp, _ = regexp.Compile("\\s+")

type reindexParams struct {
	reindexDirectory  bool
	reindexFile       bool
	initIndex         bool
	recurveIndex      bool
	ignorePrefixArray []string
	noIgnorePrefix    bool
	ignoreSuffixArray []string
	ignoreRegexp      *regexp.Regexp
	workDir           string
}

func parseReindexParams(commandDescriptor climit.CommandDescriptor) *reindexParams {
	args := reindexParams{}

	args.reindexDirectory = commandDescriptor.GetBoolOptionValue("d")
	args.reindexFile = commandDescriptor.GetBoolOptionValue("f")
	// 如果既没有指定排序的目标是目录还是文件，那么就同时对目录和文件进行排序
	if !args.reindexFile && !args.reindexDirectory {
		args.reindexDirectory = true
		args.reindexFile = true
	}

	args.recurveIndex = commandDescriptor.GetBoolOptionValue("r")

	args.initIndex = commandDescriptor.GetBoolOptionValue("i")

	args.noIgnorePrefix = commandDescriptor.GetBoolOptionValue("noIgnorePrefix")
	if args.noIgnorePrefix {
		args.ignorePrefixArray = []string{}
	} else {
		ignorePrefix := commandDescriptor.GetStringOptionValue("ignorePrefix", "_")
		args.ignorePrefixArray = strings.Split(ignorePrefix, ",")
	}

	ignoreSuffix := commandDescriptor.GetStringOptionValue("ignoreSuffix", "")
	if ignoreSuffix == "" {
		args.ignoreSuffixArray = []string{}
	} else {
		args.ignoreSuffixArray = strings.Split(ignoreSuffix, ",")
	}

	ignoreRegex := commandDescriptor.GetStringOptionValue("ignoreRegexp", "")
	if ignoreRegex == "" {
		args.ignoreRegexp = nil
	} else {
		args.ignoreRegexp, _ = regexp.Compile(ignoreRegex)
	}

	args.workDir = getWorkDirectory(commandDescriptor)

	return &args
}

func (args *reindexParams) shouldIndex(dirName string) bool {
	if !args.noIgnorePrefix && len(args.ignorePrefixArray) > 0 {
		for _, prefix := range args.ignorePrefixArray {
			if strings.HasPrefix(dirName, prefix) {
				return false
			}
		}
	}

	if len(args.ignoreSuffixArray) > 0 {
		for _, suffix := range args.ignoreSuffixArray {
			if strings.HasSuffix(dirName, suffix) {
				return false
			}
		}
	}

	if args.ignoreRegexp != nil && args.ignoreRegexp.MatchString(dirName) {
		return false
	}

	return true
}

func isIndexed(name string) bool {
	return indexedNameRegexp.MatchString(name)
}

func containsSpace(name string) bool {
	return spaceRegexp.MatchString(name)
}

func getWorkDirectory(descriptor climit.CommandDescriptor) string {
	arguments := descriptor.GetArguments()
	workdir := descriptor.GetWorkDirectory()
	if len(arguments) > 1 {
		fmt.Println("一次只能对一个目录进行reindex操作")
	} else if len(arguments) == 1 {
		// 如果是相对路径，则转换成绝对路径
		if filepath.IsAbs(arguments[0]) {
			workdir = arguments[0]
		} else {
			workdir, _ = filepath.Abs(arguments[0])
		}
	}

	// 判断要进行排序的目录是否都存在
	fileInfo, err := os.Stat(workdir)
	if err != nil && os.IsNotExist(err) {
		fmt.Println("目录不存在:", workdir)
		os.Exit(2)
	} else if err != nil {
		fmt.Println(err.Error())
		os.Exit(2)
	} else if !fileInfo.IsDir() {
		fmt.Println("路径", workdir, "不是一个目录")
		os.Exit(2)
	}

	return workdir
}

func getIndexFromTerminal(names []string) int {
	for i, name := range names {
		fmt.Println(i+1, name)
	}
	for {
		sIndex := climit.ReadLineFromTerminal()
		if sIndex == "" {
			fmt.Println("请输入序号值")
			continue
		}
		if containsSpace(sIndex) {
			fmt.Println("请不要输入空格或者制表符类似的空白字符，请重新输入序号值")
			continue
		}
		if sIndex == "q" {
			os.Exit(0)
		}
		if sIndex == "s" {
			return 0
		}
		if index, err := strconv.Atoi(sIndex); err != nil || index < 1 || index > len(names) {
			fmt.Println("请输入正确的序号值")
			continue
		} else if err == nil || index < 1 || index > len(names) {
			return index
		}
	}
}

func getIndexesFromTerminal(names []string) []int {
	for i, name := range names {
		fmt.Println(i+1, name)
	}
out:
	for {
		sIndexes := climit.ReadLineFromTerminal()
		if sIndexes == "" {
			fmt.Println("请输入序号值")
			continue
		}
		if containsSpace(sIndexes) {
			fmt.Println("请不要输入空格或者制表符类似的空白字符，请重新输入序号值")
			continue
		}
		if sIndexes == "q" {
			os.Exit(0)
		}
		if sIndexes == "s" {
			return nil
		}
		if sIndexes == "" {
			fmt.Println("请输入正确的序号值，可以输入多个序号值，多个序号值之间使用英文逗号进行分隔")
			continue
		}
		sIndexArray := strings.Split(sIndexes, ",")
		indexes := []int{}
		for _, sIndex := range sIndexArray {
			if index, err := strconv.Atoi(sIndex); err != nil || index < 1 || index > len(names) {
				fmt.Println("序号值", sIndex, "不合法")
				fmt.Println("请输入正确的序号值，可以输入多个序号值，多个序号值之间使用英文逗号进行分隔")
				continue out
			} else {
				indexes = append(indexes, index)
			}
		}
		return indexes
	}
}

func renameWithIndex(root string, indexedNames []string, unIndexedNames []string, initIndex bool) int {

	toReindexDirCount := len(indexedNames)
	if initIndex {
		toReindexDirCount = len(indexedNames) + len(unIndexedNames)
	}

	if toReindexDirCount == 0 {
		return 0
	}

	renameCount := 0

	indexLength := len(fmt.Sprintf("%d", toReindexDirCount))

	nameDisplayWidth := climit.GetMaxDisplayWidth(indexedNames) + 3

	for index, oldName := range indexedNames {
		newNameFormat := fmt.Sprintf("%%0%dd0-%s", indexLength+1, strings.SplitN(oldName, "-", 2)[1])
		newName := fmt.Sprintf(newNameFormat, index+1)
		if newName == oldName {
			continue
		}
		if rename(root, oldName, newName, nameDisplayWidth) {
			renameCount++
		}
	}
	if !initIndex {
		return renameCount
	}
	startIndex := len(indexedNames) + 1
	for index, oldName := range unIndexedNames {
		newNameFormat := fmt.Sprintf("%%0%dd0-%s", indexLength+1, oldName)
		newName := fmt.Sprintf(newNameFormat, startIndex+index)
		if rename(root, oldName, newName, nameDisplayWidth) {
			renameCount++
		}
	}
	return renameCount
}

func rename(root string, oldName string, newName string, nameDisplayWidth int) bool {
	oldPath := path.Join(root, oldName)
	newPath := path.Join(root, newName)
	_, err := os.Stat(newPath)
	// 新路径已经存在的情况下，拼接后缀
	if err == nil {
		newPath = fmt.Sprintf("%s-reindex_on_%s", newPath, time.Now().UnixMilli())
	}
	renameErr := os.Rename(oldPath, newPath)
	if renameErr != nil {
		fmt.Println(renameErr.Error())
		return false
	}
	fmt.Printf("%s -> %s\n", climit.GetDisplayString(oldName, nameDisplayWidth, ' ', true), newName)
	return true
}

func reindex(pathRoot string, params *reindexParams) {
	dirEntities, err := os.ReadDir(pathRoot)
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(3)
	}

	if len(dirEntities) == 0 {
		fmt.Printf("%s is a empty directory and not need to reindex\n", path.Join(pathRoot))
		fmt.Println()
		return
	}

	indexedDirectories := make([]string, 0)
	unIndexedDirectories := make([]string, 0)
	indexedFiles := make([]string, 0)
	unIndexedFiles := make([]string, 0)

	for _, entity := range dirEntities {
		dirName := entity.Name()
		// 如果符合被忽略的条件，直接忽略
		if !params.shouldIndex(dirName) {
			continue
		}
		if entity.IsDir() {
			if isIndexed(dirName) {
				indexedDirectories = append(indexedDirectories, dirName)
			} else {
				unIndexedDirectories = append(unIndexedDirectories, dirName)
			}
		} else {
			if isIndexed(dirName) {
				indexedFiles = append(indexedFiles, dirName)
			} else {
				unIndexedFiles = append(unIndexedFiles, dirName)
			}
		}
	}

	// 如果递归
	if params.reindexDirectory && params.recurveIndex {
		for _, dirName := range indexedDirectories {
			reindex(path.Join(pathRoot, dirName), params)
		}
		if params.initIndex {
			for _, dirName := range unIndexedDirectories {
				reindex(path.Join(pathRoot, dirName), params)
			}
		}
	}

	if params.reindexDirectory {
		fmt.Printf("reindex directories in '%s':\n\n", pathRoot)
		fmt.Printf("\nrename %d directories.\n", renameWithIndex(pathRoot, indexedDirectories, unIndexedDirectories, params.initIndex))
		fmt.Println()
	}

	if params.reindexFile {
		fmt.Printf("reindex files in '%s':\n\n", pathRoot)
		fmt.Printf("\nrename %d files.\n", renameWithIndex(pathRoot, indexedFiles, unIndexedFiles, params.initIndex))
		fmt.Println()
	}
}

func doMoveAfter(workdir string, indexedNames []string, targetType string) {
	residueNames := []string{}
	fmt.Printf("请输入序号选择要移动的%s, 输入q结束程序, 输入s跳过%s的移动：\n", targetType, targetType)
	sourceIndex := getIndexFromTerminal(indexedNames)
	if sourceIndex == 0 {
		fmt.Println("您跳过了对", targetType, "的moveAfter操作")
		return
	}
	sourceName := indexedNames[sourceIndex-1]
	for index, name := range indexedNames {
		if index+1 != sourceIndex {
			residueNames = append(residueNames, name)
		}
	}
	fmt.Printf("您选择移动的%s为: %s\n", targetType, sourceName)

	fmt.Printf("请输入序号选择要移动到哪个%s之后, 输入q结束程序, 输入s跳过%s的移动：\n", targetType, targetType)
	targetIndex := getIndexFromTerminal(residueNames)
	if targetIndex == 0 {
		fmt.Println("您跳过了对", targetType, "的moveAfter操作")
		return
	}
	targetName := residueNames[targetIndex-1]
	fmt.Println("您选择移动到:", targetName, "之后")
	toReindexNames := []string{}
	for _, dirName := range residueNames {
		toReindexNames = append(toReindexNames, dirName)
		if dirName == targetName {
			toReindexNames = append(toReindexNames, sourceName)
		}
	}
	fmt.Println("正在将", sourceName, "移动到", targetName, "之后: ")
	renameCount := renameWithIndex(workdir, toReindexNames, []string{}, false)
	fmt.Println("重命名了", renameCount, "个", targetType)
}

func runMoveAfter(commandDescriptor climit.CommandDescriptor) {
	workdir := getWorkDirectory(commandDescriptor)
	moveDirectory := commandDescriptor.GetBoolOptionValue("d")
	moveFile := commandDescriptor.GetBoolOptionValue("f")
	if !moveDirectory && !moveFile {
		moveDirectory = true
		moveFile = true
	}
	dirEntities, err := os.ReadDir(workdir)
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(3)
	}

	if len(dirEntities) == 0 {
		fmt.Printf("%s is a empty directory and not need to reindex\n", workdir)
		fmt.Println()
		return
	}

	indexedDirectories := make([]string, 0)
	indexedFiles := make([]string, 0)
	for _, entity := range dirEntities {
		dirName := entity.Name()
		if !isIndexed(dirName) {
			continue
		}

		if entity.IsDir() {
			indexedDirectories = append(indexedDirectories, dirName)
		} else {
			indexedFiles = append(indexedFiles, dirName)
		}
	}

	if moveDirectory && len(indexedDirectories) < 2 {
		fmt.Println("索引过的目录个数小于2, 无法进行目录的moveAfter")
	} else if moveDirectory {
		fmt.Println("对索引过的目录执行moveAfter操作")
		doMoveAfter(workdir, indexedDirectories, "目录")
	}

	if moveFile && len(indexedFiles) < 2 {
		fmt.Println("索引过的文件个数小于2, 无法进行文件的moveAfter")
	} else if moveFile {
		fmt.Println("对索引过的文件执行moveAfter操作")
		doMoveAfter(workdir, indexedFiles, "文件")
	}
}

func runMoveBefore(descriptor climit.CommandDescriptor) {
	workdir := getWorkDirectory(descriptor)
	moveDirectory := descriptor.GetBoolOptionValue("d")
	moveFile := descriptor.GetBoolOptionValue("f")
	if !moveDirectory && !moveFile {
		moveDirectory = true
		moveFile = true
	}
	dirEntities, err := os.ReadDir(workdir)
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(3)
	}

	if len(dirEntities) == 0 {
		fmt.Printf("%s is a empty directory and not need to reindex\n", workdir)
		fmt.Println()
		return
	}

	indexedDirectories := make([]string, 0)
	indexedFiles := make([]string, 0)
	for _, entity := range dirEntities {
		dirName := entity.Name()
		if !isIndexed(dirName) {
			continue
		}

		if entity.IsDir() {
			indexedDirectories = append(indexedDirectories, dirName)
		} else {
			indexedFiles = append(indexedFiles, dirName)
		}
	}

	if moveDirectory && len(indexedDirectories) < 2 {
		fmt.Println("索引过的目录个数小于2, 无法进行目录的moveBefore")
	} else if moveDirectory {
		fmt.Println("对索引过的目录执行moveBefore操作")
		doMoveBefore(workdir, indexedDirectories, "目录")
	}

	if moveFile && len(indexedFiles) < 2 {
		fmt.Println("索引过的文件个数小于2, 无法进行文件的moveBefore")
	} else if moveFile {
		fmt.Println("对索引过的文件执行moveBefore操作")
		doMoveBefore(workdir, indexedFiles, "文件")
	}

}

func doMoveBefore(workdir string, indexedNames []string, targetType string) {
	residueNames := []string{}
	fmt.Printf("请输入序号选择要移动的%s, 输入q结束程序, 输入s跳过%s的移动：\n", targetType, targetType)
	sourceIndex := getIndexFromTerminal(indexedNames)
	if sourceIndex == 0 {
		fmt.Println("您跳过了对", targetType, "的moveBefore操作")
		return
	}
	sourceName := indexedNames[sourceIndex-1]
	for index, name := range indexedNames {
		if index+1 != sourceIndex {
			residueNames = append(residueNames, name)
		}
	}
	fmt.Printf("您选择移动的%s为: %s\n", targetType, sourceName)

	fmt.Printf("请输入序号选择要移动到哪个%s之后, 输入q结束程序, 输入s跳过%s的移动：\n", targetType, targetType)
	targetIndex := getIndexFromTerminal(residueNames)
	if targetIndex == 0 {
		fmt.Println("您跳过了对", targetType, "的moveBefore操作")
		return
	}
	targetName := residueNames[targetIndex-1]
	fmt.Println("您选择移动到:", targetName, "之前")
	toReindexNames := []string{}
	for _, dirName := range residueNames {
		if targetName == dirName {
			toReindexNames = append(toReindexNames, sourceName)
		}
		toReindexNames = append(toReindexNames, dirName)
	}
	fmt.Println("正在将", sourceName, "移动到", targetName, "之前: ")
	renameCount := renameWithIndex(workdir, toReindexNames, []string{}, false)
	fmt.Println("重命名了", renameCount, "个", targetType)
}

func runMoveToTop(descriptor climit.CommandDescriptor) {
	workdir := getWorkDirectory(descriptor)
	moveDirectory := descriptor.GetBoolOptionValue("d")
	moveFile := descriptor.GetBoolOptionValue("f")
	if !moveDirectory && !moveFile {
		moveDirectory = true
		moveFile = true
	}
	dirEntities, err := os.ReadDir(workdir)
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(3)
	}

	if len(dirEntities) == 0 {
		fmt.Printf("%s is a empty directory and not need to reindex\n", workdir)
		fmt.Println()
		return
	}

	indexedDirectories := make([]string, 0)
	indexedFiles := make([]string, 0)
	for _, entity := range dirEntities {
		dirName := entity.Name()
		if !isIndexed(dirName) {
			continue
		}

		if entity.IsDir() {
			indexedDirectories = append(indexedDirectories, dirName)
		} else {
			indexedFiles = append(indexedFiles, dirName)
		}
	}

	if moveDirectory && len(indexedDirectories) < 2 {
		fmt.Println("索引过的目录个数小于2, 无法进行目录的moveToTop")
	} else if moveDirectory {
		fmt.Println("对索引过的目录执行moveToTop操作")
		doMoveToTop(workdir, indexedDirectories, "目录")
	}

	if moveFile && len(indexedFiles) < 2 {
		fmt.Println("索引过的文件个数小于2, 无法进行文件的moveToTop")
	} else if moveFile {
		fmt.Println("对索引过的文件执行moveToTop操作")
		doMoveToTop(workdir, indexedFiles, "文件")
	}

}

func doMoveToTop(workdir string, indexedNames []string, targetType string) {
	toReindexNames := []string{}
	fmt.Printf("请输入序号选择要移动的%s, 输入q结束程序, 输入s跳过%s的移动：\n", targetType, targetType)
	sourceIndex := getIndexFromTerminal(indexedNames)
	if sourceIndex == 0 {
		fmt.Println("您跳过了对", targetType, "的moveToTop操作")
		return
	}
	sourceName := indexedNames[sourceIndex-1]

	toReindexNames = append(toReindexNames, sourceName)

	for index, name := range indexedNames {
		if index+1 != sourceIndex {
			toReindexNames = append(toReindexNames, name)
		}
	}

	fmt.Println("正在将", sourceName, "移动到首位: ")
	renameCount := renameWithIndex(workdir, toReindexNames, []string{}, false)
	fmt.Println("重命名了", renameCount, "个", targetType)
}

func runMoveToBottom(descriptor climit.CommandDescriptor) {
	workdir := getWorkDirectory(descriptor)
	moveDirectory := descriptor.GetBoolOptionValue("d")
	moveFile := descriptor.GetBoolOptionValue("f")
	if !moveDirectory && !moveFile {
		moveDirectory = true
		moveFile = true
	}
	dirEntities, err := os.ReadDir(workdir)
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(3)
	}

	if len(dirEntities) == 0 {
		fmt.Printf("%s is a empty directory and not need to reindex\n", workdir)
		fmt.Println()
		return
	}

	indexedDirectories := make([]string, 0)
	indexedFiles := make([]string, 0)
	for _, entity := range dirEntities {
		dirName := entity.Name()
		if !isIndexed(dirName) {
			continue
		}

		if entity.IsDir() {
			indexedDirectories = append(indexedDirectories, dirName)
		} else {
			indexedFiles = append(indexedFiles, dirName)
		}
	}

	if moveDirectory && len(indexedDirectories) < 2 {
		fmt.Println("索引过的目录个数小于2, 无法进行目录的moveToBottom")
	} else if moveDirectory {
		fmt.Println("对索引过的目录执行moveToBottom操作")
		doMoveToBottom(workdir, indexedDirectories, "目录")
	}

	if moveFile && len(indexedFiles) < 2 {
		fmt.Println("索引过的文件个数小于2, 无法进行文件的moveToBottom")
	} else if moveFile {
		fmt.Println("对索引过的文件执行moveToBottom操作")
		doMoveToBottom(workdir, indexedFiles, "文件")
	}

}

func doMoveToBottom(workdir string, indexedNames []string, targetType string) {
	toReindexNames := []string{}
	fmt.Printf("请输入序号选择要移动的%s, 输入q结束程序, 输入s跳过%s的移动：\n", targetType, targetType)
	sourceIndex := getIndexFromTerminal(indexedNames)
	if sourceIndex == 0 {
		fmt.Println("您跳过了对", targetType, "的moveToBottom操作")
		return
	}
	sourceName := indexedNames[sourceIndex-1]

	for index, name := range indexedNames {
		if index+1 != sourceIndex {
			toReindexNames = append(toReindexNames, name)
		}
	}

	toReindexNames = append(toReindexNames, sourceName)

	fmt.Println("正在将", sourceName, "移动到末尾: ")
	renameCount := renameWithIndex(workdir, toReindexNames, []string{}, false)
	fmt.Println("重命名了", renameCount, "个", targetType)
}

var illegalCharRegexp, _ = regexp.Compile("[/,&%$#@^*]+")

func runUnIndex(descriptor climit.CommandDescriptor) {
	workdir := getWorkDirectory(descriptor)
	moveDirectory := descriptor.GetBoolOptionValue("d")
	moveFile := descriptor.GetBoolOptionValue("f")
	if !moveDirectory && !moveFile {
		moveDirectory = true
		moveFile = true
	}
	dirEntities, err := os.ReadDir(workdir)
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(3)
	}

	if len(dirEntities) == 0 {
		fmt.Printf("%s 空目录不需要进行reindex操作\n", workdir)
		fmt.Println()
		return
	}

	indexedDirectories := make([]string, 0)
	indexedFiles := make([]string, 0)
	for _, entity := range dirEntities {
		dirName := entity.Name()
		if !isIndexed(dirName) {
			continue
		}

		if entity.IsDir() {
			indexedDirectories = append(indexedDirectories, dirName)
		} else {
			indexedFiles = append(indexedFiles, dirName)
		}
	}

	if moveDirectory && len(indexedDirectories) == 0 {
		fmt.Println("不存在索引过的目录, 无法进行目录的unIndex")
	} else if moveDirectory {
		fmt.Println("对索引过的目录执行unIndex操作")
		doUnIndex(workdir, indexedDirectories, "目录")
	}

	if moveFile && len(indexedFiles) == 0 {
		fmt.Println("不存在索引过的文件, 无法进行文件的unIndex")
	} else if moveFile {
		fmt.Println("对索引过的文件执行unIndex操作")
		doUnIndex(workdir, indexedFiles, "文件")
	}

}

func doUnIndex(workdir string, indexedNames []string, targetType string) {
	toReindexNames := []string{}
	fmt.Printf("请输入序号选择要移动的%s, 可以选择多个序号，多个序号之间用英文逗号进行分隔，输入q结束程序, 输入s跳过%s的移动：\n", targetType, targetType)
	sourceIndexes := getIndexesFromTerminal(indexedNames)
	if sourceIndexes == nil || len(sourceIndexes) == 0 {
		fmt.Println("您跳过了对", targetType, "的unIndex操作")
		return
	}
	sourceIndexSet := climit.SetOf(sourceIndexes)
	sourceNames := []string{}
	for index, name := range indexedNames {
		if sourceIndexSet.Contains(index + 1) {
			sourceNames = append(sourceNames, name)
		} else {
			toReindexNames = append(toReindexNames, name)
		}
	}
	fmt.Println("您选择对如下", targetType, "进行unIndex操作：")
	for _, sourceName := range sourceNames {
		fmt.Println(sourceName)
	}
	fmt.Println("请为他们输入新的前缀，之后将使用新的前缀对它们进行重命名，输入回车将使用默认前缀 '_' ")
	prefix := ""
	for {
		prefix = climit.ReadLineFromTerminal()
		if prefix == "" {
			prefix = "_"
			break
		}
		if containsSpace(prefix) {
			fmt.Println("前缀不能包含空白字符，请重新输入正确的前缀")
			continue
		}
		if illegalCharRegexp.MatchString(prefix) {
			fmt.Println("前缀不能包含诸如 /,&%$#@^* 的特殊字符，请重新输入正确的前缀")
			continue
		}
		if isIndexed(prefix) {
			fmt.Println("您输入的前缀", prefix, "会让reindex认为该名称是一个索引过的，会造成重命名之后名称顺序的错乱，请重新输入索引")
			continue
		}
		break
	}
	fmt.Println("新前缀是:", prefix)
	fmt.Println("正在进行取消索引操作：")
	nameDisplayWidth := climit.GetMaxDisplayWidth(sourceNames) + 3
	for _, name := range sourceNames {
		rename(workdir, name, prefix+name, nameDisplayWidth)
	}
	if len(toReindexNames) > 0 {
		doReindex := "n"
		fmt.Println("是否对剩余的索引过的名称进行reindex操作？y/n")
		for {
			doReindex = climit.ReadLineFromTerminal()
			if doReindex != "n" && doReindex != "y" {
				fmt.Println("是否对剩余的索引过的名称进行reindex操作？y/n")
			} else {
				break
			}
		}
		if doReindex == "y" {
			renameWithIndex(workdir, toReindexNames, []string{}, false)
		}
	}
}
